/*
 ********************************************************************************
 *                      桂林聚联科技有限公司
 *                           Copyright
 *
 *  文件描述 ： OTDR控制算法层对外接口声明，向外部模块提供功能函数接口
 *
 *
 *  文件名称 ： otdrtestinterface.h
 *  创建者   ： 彭怀敏
 *  创建日期 ： 2016-10-27 09:59:18
 *  当前版本 ： 
 ********************************************************************************
*/
#ifndef _OTDRTESTINTERFACE_H__
#define _OTDRTESTINTERFACE_H__

#ifdef __cplusplus
extern "C" {
#endif  // __cplusplus

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>

#ifdef X86      // X86 simulate, use data from files ONLY
    #define DATA_SPI    0
    #define DATA_FILE   1
#else           // ARM926 platform
	#ifdef DATA_FILE
        #undef DATA_FILE
	    #define DATA_SPI    0
	    #define DATA_FILE   1
	#else
	    #define DATA_SPI    1
	    #define DATA_FILE   0
	#endif
#endif

/*************************************************************************************************/
/**************************************** 命令宏定义 *********************************************/
/*************************************************************************************************/
// 测试参数定义
typedef struct
{
    int ChanNum;            // Otdr Channel
    int OtdrMode;           // OTDR测试模式：0为空闲，1为平均，2为实时
    int RefreshPeriod_ms;   // 刷新周期，如果不刷新，则让其等于测试时间
    int DataNum;            // 采样点数，当前固定为32000
    unsigned int SampleRate_Hz;      // 采样率，由算法层上传，调用者只读

    int Lambda_nm;          // 波长
    int MeasureLength_m;    // 量程
    int PulseWidth_ns;      // 脉宽
    int MeasureTime_ms;     // 测试时间
    float n;                // 折射率
    float EndThreshold;     // 结束门限
    float NonReflex;        // 非反射门限

    int slice_ms;           // 启动FPGA进行测试的时间片
    int rsvd1;              // use as the parameter "User Offset x1000"
    int rsvd2;
}OtdrTestParam_t;

// 拼接参数定义
typedef struct
{
    int PowerMode;
    int ConcatPoint;

    int LowPower;
    int LowRcv;

    int HighPower;
    int HighRcv;
}ConcatParam_t;

// 事件点结构以及光纤段结构, 如果有N个事件点，则对应N-1个光纤段
typedef struct
{
    int EventStart;             // 事件点的前点
    int EventEnd;               // 事件点的末点
    int EventType;              // 事件的类型：开始，结束，反射，非反射
    float EventReturnloss;      // 事件点的回损
    float EventInsertloss;      // 事件点的插损
    float EventTotalloss;       // 事件点的累计损耗
}EventPoint_t;

// OTDR工作模式
#define OTDR_MODE_IDLE          0       // 空闲模式
#define OTDR_MODE_AVG           1       // 平均模式
#define OTDR_MODE_REALTIME      2       // 实时模式
#define OTDR_MODE_RECORRECT     101     // 校正模式
#define OTDR_MODE_CYCLE_TEST    102     // 循环测试模式

#define OTDR_MODE_ZZ            1001    // 追踪模式
#define OTDR_MODE_PC            1002    // 普查模式

// 测试模式
#define MEASURE_MODE_AUTO       0       // 自动测试模式
#define MEASURE_MODE_MANUAL     1       // 手动测试模式

// 功率控制模式
#define POWER_MODE_UNDEF                0           // 初始未定义
#define POWER_MODE_LOW                  1           // 使用低功率
#define POWER_MODE_HIGH                 2           // 使用高功率
#define POWER_MODE_CONCAT               3           // 使用混合功率

typedef struct
{
    int   FiberSectionLen;          // 或者光纤段的长度
    float FiberSectionLoss;         // 光纤段的段损耗
    float FiberSectionAttenCoef;    // 光纤段的段衰减系数
}FiberSection_t;

// OTDR全部测试数据
#define	MAX_EVENT_NUM		100
#define RSVD_FLOAT          8192.0      // 浮点数保留值，表明该值无法确定或无需确定
typedef struct
{
    int valid;              // 有效数据指示，1为只包含测试参数，2为包含测试参数及曲线数据，3为包含全部数据
            
    // parameter
    OtdrTestParam_t tp;     // 返回测试参数
    
    // Curve
    float *Ai;              // 指向DataNum个float的缓冲区，那里存储着对数曲线数据
    
    // Event
    int EventNum;           // 事件点数目
    EventPoint_t ep[MAX_EVENT_NUM];     // 100 events

    // Fiber
    int FiberNum;           // 光纤段数目 = 事件点数目 - 1
    FiberSection_t fs[MAX_EVENT_NUM];   // 99 fibers

    float FiberLen;
    float FiberAttenCoef;
    float FiberLoss;
}OtdrTestResult_t;

// OTDR回帧命令数据结构
#define	E_CMD_OK                0   // 成功处理命令
#define	E_STOPPED               1   // Measure stopped without data
#define	E_TEST_PARAM            2   // 非法 test parameter
#define	E_MEM_ALLOC             3   // memory alloc failed
#define	E_FPGA_ERR              4   // fpga timeout, or spi error
#define	E_CONCAT                6   // 拼接时，低功率曲线动态太低
#define	E_FAILED                10  // 多次重测仍然出错，则测试失败

// 最值宏定义
#define	MAX(a, b)	    (((a) > (b)) ? (a) : (b))
#define	MIN(a, b)	    (((a) < (b)) ? (a) : (b))
    
/********************************************************************************/
typedef struct
{
    int ChanNum;            // Otdr Channel
    int DataNum;            // 采样点数，当前固定为32000
    unsigned int SampleRate_Hz;      // 采样率，由算法层上传，调用者只读

    int Lambda_nm;          // 波长
    int MeasureLength_m;    // 量程
    int PulseWidth_ns;      // 脉宽
    int MeasureTime_ms;     // 测试时间

    int powerlevel;         // laser power
    int rcv;                // receiver
    int apdv;               // apdV
}OtdrSpTestParam_t;

typedef struct
{
    OtdrSpTestParam_t sp;
    int *data;
}OtdrSpTestResult_t;

#include "Event.h"

/*
 ********************************************************************************
 *  向外部提供的接口声明
 ********************************************************************************
*/
#ifndef _DEVICE_INDEPENDENT_

#include <unistd.h>
#include <netinet/in.h>
#include "fpga-2016.h"

// 设备信息结构
typedef struct
{
    pthread_mutex_t mutex_fpga; // 给FPGA上锁，调用者负责初始化
    struct fpga_dev *fpga;
}DeviceInfo_t;

// 打开VFL
int openVFL(DeviceInfo_t *device);
// 关闭VFL
int closeVFL(DeviceInfo_t *device);
// 闪烁VFL
int twinkleVFL(DeviceInfo_t *device);

// 解析算法模块的配置文件，并更新相应的变量
void otdr_open(DeviceInfo_t *dev);
int configOtdrAlgo(DeviceInfo_t *device, char *iniConfigFile, int DataNum);

// 读取OTDR硬件配置信息
// otdr_name    : 型号字符串，如"SV20A", "MV10A"等
// OtdrLasersMM : 多模激光器波长列表，以0结束，如[850, 1300, 0]
// OtdrLasersSM : 单模激光器波长列表，以0结束，如[1310, 1550, 0]
// VFLLasers    : 红光VFL波长列表，以0结束，如[650, 0]
// type         : 动态类型，其值为'A', 'B', 'C', '0'
// return value : 0 --> 正确匹配型号    1 --> 无法匹配型号
int getHWInfo(DeviceInfo_t *device, \
        char otdr_name[], \
        int *otdr_code, \
        int OtdrLasersMM[], \
        int OtdrLasersSM[], \
        int VFLLasers[], \
        int *type);

// 启动测试接口函数
int startOtdrTest(OtdrTestParam_t *tp, 
            ConcatParam_t *cp, \
            int (*ResultCopyBack)(OtdrTestResult_t *, OtdrTestResult_t *, int), \
            OtdrTestResult_t *OtdrTestResult, \
            int (*stop)(void), \
            DeviceInfo_t *device);

int startTest(OtdrTestParam_t *tp, 
            int (*ResultCopyBack)(OtdrTestResult_t *, OtdrTestResult_t *, int), \
            OtdrTestResult_t *OtdrTestResult, \
            int (*stop)(void), \
            DeviceInfo_t *device);

// 自动测试匹配量程脉宽
int adaptTestParam(OtdrTestParam_t *tp, \
            OtdrTestParam_t *retTp, \
            int (*stop)(void), \
            DeviceInfo_t *device);

// 测试获取光纤连接状态
int getConnectState(OtdrTestParam_t *tp, \
            int *state, \
            int (*stop)(void), \
            DeviceInfo_t *device);

// 测试获取拼接状态
int getConcat(OtdrTestParam_t *tp, \
            ConcatParam_t *cp, \
            int (*stop)(void), \
            DeviceInfo_t *device);

// 通信光检测
int detectCommunicationLight(DeviceInfo_t *device , \
            int *state);

// 启动特定参数测试
int specifiedTest(OtdrSpTestParam_t *sp, \
            int (*ResultCopyBack)(OtdrSpTestResult_t *, OtdrSpTestResult_t *, int), \
            OtdrSpTestResult_t *OtdrSpTestResult, \
            DeviceInfo_t *device);

#endif   /* _DEVICE_INDEPENDENT_ */

// 使用最小二乘法将OTDR曲线的线段拟合成直线，保留事件点和噪声部分
void lsaFitOTDRData(const OtdrTestResult_t *result, float *LinearOut);
void lsaFitAB(const OtdrTestResult_t *result, int Apos, int Bpos, float *ABloss, float *ABcoef);
void getTotalLoss(const OtdrTestResult_t *result, const int pos[], float loss[], int n);

// 最小二乘法对输入数据进行线性拟合，输出常数项b和一次项系数k
void LeastSquareMethod(const float di[], int from, int to, float *k, float *b);

// save data to file
void saveint(char *filename, int buf[], int n);
void savefloat(char *filename, float buf[], int n);

///////////  点距转换函数 //////////////////////////////////////////////////////////
float getLenByIndex(unsigned int index, unsigned int frequency,float refraction);
int getIndexByLen(float len, unsigned int frequency,float refraction);
int getDisplayNumber(int measureLength , float refraction, int *displayNum);
int getFrequency (int measureLength, unsigned int * frequency);
int getPulseWidth_M2(OtdrTestParam_t *tp);
int getPulseWidthRange2(OtdrTestParam_t *tp, int *minPW, int *maxPW);
int getPulseWidth_M(int MeasureLength_m, int PulseWidth_ns);
int getPulseWidthRange(int MeasureLength_m, int *minPW, int *maxPW);
int getTemperature(int *data);
int getBatteryPower(int *p1, int *p2);
int getChargeState(int *s1, int *s2, int *ext);


#ifdef __cplusplus
}
#endif // __cplusplus

#endif	// _OTDRTESTINTERFACE_H__

